﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sustainalytics.Entities;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;

namespace Sustainalytics.ScreeningTool.Service.Tests
{
    [TestClass()]
    public class CriteriaLevel1ControllerTests
    {
        [TestMethod]
        public void Get()
        {
            Guid companyInfoCriteriaLevel1Id = Guid.NewGuid();
            Guid esgCompositeCriteriaLevel1Id = Guid.NewGuid();
            Guid businessOverviewCriteriaLevel2Id = Guid.NewGuid();
            Guid generalCriteriaLevel2Id = Guid.NewGuid();
            Guid esgEventsCriteriaLevel2Id = Guid.NewGuid();
            List<CriteriaLevel1> criteriaLevel1List = new List<CriteriaLevel1>();
            criteriaLevel1List.Add(new CriteriaLevel1() { Id = companyInfoCriteriaLevel1Id, Name = "Company info" });
            criteriaLevel1List.Add(new CriteriaLevel1() { Id = esgCompositeCriteriaLevel1Id, Name = "ESG Composite" });
            criteriaLevel1List.Add(new CriteriaLevel1() { Id = Guid.NewGuid(), Name = "EmptyTabLevel1" });
            List<CriteriaLevel2> criteriaLevel2List = new List<CriteriaLevel2>();
            criteriaLevel2List.Add(new CriteriaLevel2() { Id = businessOverviewCriteriaLevel2Id, CriteriaLevel1Id = companyInfoCriteriaLevel1Id, Name = "Business overview" });
            criteriaLevel2List.Add(new CriteriaLevel2() { Id = generalCriteriaLevel2Id, CriteriaLevel1Id = companyInfoCriteriaLevel1Id, Name = "General" });
            criteriaLevel2List.Add(new CriteriaLevel2() { Id = esgEventsCriteriaLevel2Id, CriteriaLevel1Id = esgCompositeCriteriaLevel1Id, Name = "Event Indicators" });
            criteriaLevel2List.Add(new CriteriaLevel2() { Id = Guid.NewGuid(), CriteriaLevel1Id = esgCompositeCriteriaLevel1Id, Name = "EmptyTabLevel2" });
            List<BaseCriteria> baseCriteriaList = new List<BaseCriteria>();
            baseCriteriaList.Add(new BaseCriteria() { Id = Guid.NewGuid(), Name = "Market capitalization", CriteriaEntity = "FinancialData", CriteriaEntityField = "MarketCapitalization", CriteriaLevel2Id = businessOverviewCriteriaLevel2Id, CriteriaType = CriteriaTypeEnum.CriteriaType1 });
            baseCriteriaList.Add(new BaseCriteria() { Id = Guid.NewGuid(), Name = "Number of employees", CriteriaEntity = "CompanyInfo", CriteriaEntityField = "NumberOfEmployees", CriteriaLevel2Id = generalCriteriaLevel2Id, CriteriaType = CriteriaTypeEnum.CriteriaType1 });
            baseCriteriaList.Add(new BaseCriteria() { Id = Guid.NewGuid(), Name = "Basic labour standards", CriteriaEntity = "EventIndicator", CriteriaEntityField = "BaseEventIndicatorId", CriteriaLevel2Id = esgEventsCriteriaLevel2Id, CriteriaType = CriteriaTypeEnum.CriteriaType2 });
            baseCriteriaList.Add(new BaseCriteria() { Id = Guid.NewGuid(), Name = "Business Ethics", CriteriaEntity = "EventIndicator", CriteriaEntityField = "BaseEventIndicatorId", CriteriaLevel2Id = esgEventsCriteriaLevel2Id, CriteriaType = CriteriaTypeEnum.CriteriaType2 });
            baseCriteriaList.Add(new BaseCriteria() { Id = Guid.NewGuid(), Name = "Child Labour", CriteriaEntity = "EventIndicator", CriteriaEntityField = "BaseEventIndicatorId", CriteriaLevel2Id = esgEventsCriteriaLevel2Id, CriteriaType = CriteriaTypeEnum.CriteriaType2 });


            var companyScreeningService = new Sustainalytics.ScreeningTool.BL.Fakes.StubICompanyScreening()
            {
                GetCriteriaLevelOneGuid = (id) =>
                {
                    return criteriaLevel1List.Where(cr1 => cr1.Id == id).SingleOrDefault();
                },
                GetCriteriaLevelTwoGuid = (id) =>
                {
                    return criteriaLevel2List.Where(cr2 => cr2.Id == id).SingleOrDefault();
                },
                ListCriteriaLevelOne = () =>
                {
                    return criteriaLevel1List;
                },
                ListCriteriaLevelTwoNullableOfGuid = (criteriaLevel1Id) =>
                {
                    if (criteriaLevel1Id.HasValue)
                        return criteriaLevel2List.Where(cr2 => cr2.CriteriaLevel1Id == criteriaLevel1Id).ToList();

                    return criteriaLevel2List;
                },
                ListBaseCriteriaNullableOfGuid = (criteriaLevel2Id) =>
                {
                    if (criteriaLevel2Id.HasValue)
                        return baseCriteriaList.Where(bc => bc.CriteriaLevel2Id == criteriaLevel2Id).ToList();

                    return baseCriteriaList;
                }
            };

            var criteriaLevel1Controller = Utils.setupController<CriteriaLevel1Controller>(new CriteriaLevel1Controller(companyScreeningService, null));
            
            ListOptions options = new ListOptions();
            List<CriteriaLevel1Dto> criteriaLevel1DtoList = new List<CriteriaLevel1Dto>();
            HttpResponseMessage criteriaTabs = criteriaLevel1Controller.Get(options, true);
            
            Assert.IsNotNull(criteriaTabs, "The criteria tabs should not be null.");
            Assert.IsTrue(criteriaTabs.IsSuccessStatusCode, "The request has failed.");
            Assert.IsTrue(criteriaTabs.TryGetContentValue<List<CriteriaLevel1Dto>>(out criteriaLevel1DtoList), "The response does not contain the list of criteria level 1 dto.");
            Assert.AreEqual(criteriaLevel1List.Count, criteriaLevel1DtoList.Count, "The number of criteria level 1 is different than the expected one.");
            Assert.IsFalse(criteriaLevel1DtoList.Last().IsEnabled, "The should be disabled.");
            Assert.AreEqual(criteriaLevel2List.Count(i => i.CriteriaLevel1Id == criteriaLevel1DtoList.First().Id), criteriaLevel1DtoList.First().ChildItems.Count, "The number of criteria level 2 is different than the expected one.");

            List<object> objectList = new List<object>();
            criteriaTabs = criteriaLevel1Controller.Get(options);

            Assert.IsNotNull(criteriaTabs, "The criteria tabs should not be null.");
            Assert.IsTrue(criteriaTabs.IsSuccessStatusCode, "The request has failed.");
            Assert.IsTrue(criteriaTabs.TryGetContentValue<List<object>>(out objectList), "The response does not contain the list of criteria level 1 dto.");
            Assert.AreEqual(criteriaLevel1List.Count, objectList.Count, "The number of criteria level 1 is different than the expected ones");

            criteriaTabs = criteriaLevel1Controller.Get(companyInfoCriteriaLevel1Id);
            object criteriaLevel1 = null;
            Assert.IsNotNull(criteriaTabs, "The criteria level 1 dto should not be null.");
            Assert.IsTrue(criteriaTabs.IsSuccessStatusCode, "The request has failed.");
            Assert.IsTrue(criteriaTabs.TryGetContentValue<object>(out criteriaLevel1), "The response does not contain the criteria level 1 dto.");

            criteriaTabs = criteriaLevel1Controller.Get(companyInfoCriteriaLevel1Id, true);
            CriteriaLevel1Dto criteriaLevel1Dto = null;
            Assert.IsNotNull(criteriaTabs, "The criteria level 1 dto should not be null.");
            Assert.IsTrue(criteriaTabs.IsSuccessStatusCode, "The request has failed.");
            Assert.IsTrue(criteriaTabs.TryGetContentValue<CriteriaLevel1Dto>(out criteriaLevel1Dto), "The response does not contain the criteria level 1 dto.");
            Assert.AreEqual(companyInfoCriteriaLevel1Id, criteriaLevel1Dto.Id, "The id of the criteria level 1 is different than the excpected one.");
        }
    }
}
